#ifndef _XX_YY_BMOCK_IN_ARG_VAL
#define _XX_YY_BMOCK_IN_ARG_VAL

#include <boost/lexical_cast.hpp>
#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/static_assert.hpp>
#include "bmock_arg_val.hpp"
#include "bmock_raw_mem.hpp"

namespace bmock {
	struct in_arg_val : public arg_val	
	{		
		in_arg_val(const char *n,const std::string &val);
		in_arg_val(const char *n,const std::string &val,const raw_mem& rm);
	protected:
		virtual bool        validate(const arg_checker &chk,const std::string &v) const;		
		virtual bool		validate_no_msg(const arg_checker &chk, const std::string &v) const;		
		bool              null_supplied() const;
		std::string		  get_in_value(const arg_checker &chk) const;
		std::string       get_in_value() const;
		void              print(std::ostream &os) const;
		void              print_value(std::ostream &os) const;
		virtual				  ~in_arg_val();

		std::string       value_;
		raw_mem				rm_;
	};
	inline arg_val *make_in_arg_val(const char *const n,const char &value) {
		return new in_arg_val(n,__get_value(value));
	}
	inline arg_val *make_in_arg_val(const char *const n,const unsigned char &value) {
		return new in_arg_val(n,__get_value(value));
	}
	inline arg_val *make_in_arg_val(const char *const n,const raw_mem &rm) {
		return new in_arg_val(n,rm.get_value(),rm);
	}
	inline arg_val *make_in_arg_val(const char *const n,const char *const ptr) {
		return new in_arg_val(n,__get_value(ptr));
	}
	inline arg_val *make_in_arg_val(const char *const n,char *const ptr) {
		return new in_arg_val(n,__get_value(ptr));
	}
	template<typename T> inline arg_val *make_in_arg_val(const char *const n,const T *const ptr) {
		return new in_arg_val(n,__get_value(ptr));
	}
	template<typename T> inline arg_val *make_in_arg_val(const char *const n,const T &value) {
		return make_in_arg_val(n,&value);
	}
	
	template <class T>
	inline typename boost::disable_if<boost::is_function<T>, arg_val>::type 
		*make_in_arg_val(const char *const n,T *const ptr) {
			return make_in_arg_val(n,(const T *const)ptr);
	}
	template <class T>
	inline typename boost::enable_if<boost::is_function<T>, arg_val>::type 
		*make_in_arg_val(const char *const n,T ptr) {
			mem_func_ptr_holder<T> c_ptr(ptr);
			std::string val(BMOCK_HEX_PREFIX+boost::lexical_cast<std::string>(c_ptr.vptr_));
			return new in_arg_val(n,val);
	}
	template <typename T>
	struct is_function_pointer : public
		boost::mpl::or_<
		boost::is_member_function_pointer<T>,
		boost::mpl::and_<
		boost::is_function<typename boost::remove_pointer<T>::type>,
		typename boost::is_pointer<T> 
		>
		> {};
	template<typename T>
	inline typename boost::enable_if<typename boost::is_member_function_pointer<T>::type,arg_val>::type
		*make_in_func_ptr_arg_val(const char *const n,T ptr) {
			mem_func_ptr_holder<T> c_ptr(ptr);
			std::string val(BMOCK_HEX_PREFIX+boost::lexical_cast<std::string>(c_ptr.vptr_));
			return new in_arg_val(n,val);
	}
	template<typename T>
	inline typename boost::enable_if<typename boost::is_function<T>::type,arg_val>::type
		*make_in_func_ptr_arg_val(const char *const n,T *const ptr) {
			mem_func_ptr_holder<T*> c_ptr(ptr);
			std::string val(BMOCK_HEX_PREFIX+boost::lexical_cast<std::string>(c_ptr.vptr_));
			return new in_arg_val(n,val);
	}
	template<typename T>
	inline typename boost::disable_if<typename boost::is_function<T>::type,arg_val>::type
		*make_in_func_ptr_arg_val(const char *const n,T *const ptr) {
			std::string val(BMOCK_HEX_PREFIX+boost::lexical_cast<std::string>(ptr));
			return new in_arg_val(n,val);
	}
	template<typename T>
	inline arg_val *make_in_ptr_arg_val(const char *const n,const T *const ptr) {
		return make_in_func_ptr_arg_val(n,(T *const)ptr);
	}
	template<typename T>
	inline arg_val *make_in_ptr_arg_val(const char *const n,T *const ptr) {
		return make_in_func_ptr_arg_val(n,ptr);
	}
	
	template<typename T>
	inline typename boost::disable_if<boost::is_member_function_pointer<T>,arg_val>::type 
		*make_in_ptr_arg_val(const char *const n,T &ref) {
			return make_in_func_ptr_arg_val(n,&ref);
	}
	template<typename T>
	inline typename boost::enable_if<boost::is_member_function_pointer<T>,arg_val>::type 
		*make_in_ptr_arg_val(const char *const n,T ptr) {
			return make_in_func_ptr_arg_val(n,ptr);
	}
	inline arg_val *make_in_ptr_arg_val(const char *const n,const char *const ptr) {
		return make_in_ptr_arg_val(n,(const void *const)ptr);
	}
	inline arg_val *make_in_ptr_arg_val(const char *const n,char *const ptr) {
		return make_in_ptr_arg_val(n,(const void *const)ptr);
	}
	inline arg_val *make_in_ptr_arg_val(const char *const n,const unsigned char *const ptr) {
		return make_in_ptr_arg_val(n,(const void *const)ptr);
	}
	inline arg_val *make_in_ptr_arg_val(const char *const n,unsigned char *const ptr) {
		return make_in_ptr_arg_val(n,(const void *const)ptr);
	}
}

#include <boost/preprocessor/stringize.hpp>

#define __BMOCK_USE_IN(ARG)\
	bmock::make_in_arg_val(BOOST_PP_STRINGIZE(ARG),ARG)

#define __BMOCK_USE_CLBK(ARG)\
	bmock::make_in_func_ptr_arg_val(BOOST_PP_STRINGIZE(ARG),ARG)

#define __BMOCK_USE_IN_PTR(ARG)\
	bmock::make_in_ptr_arg_val(BOOST_PP_STRINGIZE(ARG),ARG)

#define __BMOCK_USE_RAW_IN(ARG,LEN)\
	bmock::make_in_arg_val(BOOST_PP_STRINGIZE(ARG),bmock::raw_mem(ARG,LEN))


#endif
